﻿using FX_API.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static FX_API.Delegates;

namespace FX_API.Request
{
    public abstract class FXBaseQueryService<T> where T : FXBaseEntity, new()
    {
        public HandlerFunc InfoFunc { protected get; set; }
        public HandlerFunc ErrFunc { protected get; set; }
        public HandlerFunc WarningFunc { protected get; set; }

        public static readonly List<OrdersItem> EMPTY_ORDER_RULES = new List<OrdersItem>();
        public static readonly List<FiltersItem> EMPTY_FILTER_RULES = new List<FiltersItem>();
        public static readonly List<string> EMPTY_FIELD_PROJECTION = new List<string>();

        /// <summary>
        /// 纷享apiName, 发送请求时标识接口
        /// </summary>
        protected abstract string ApiName { get; }

        /// <summary>
        /// 方法描述，用于日志的标准输出
        /// </summary>
        protected abstract string MethodDescription { get; }

        /// <summary>
        /// 默认的过滤规则，默认为空，即全量获取
        /// </summary>
        protected virtual List<FiltersItem> DefaultFilterRules { get; } = EMPTY_FILTER_RULES;

        /// <summary>
        /// 纷享返回字段的列表，默认为Model类的属性名列表
        /// </summary>
        protected virtual List<string> FieldProjection
        {
            get => typeof(T).GetProperties().Select(p => p.Name).ToList();
        }

        /// <summary>
        /// 必填字段列表，用于检验字段缺失
        /// </summary>
        protected virtual List<string> NecessaryFields { get; } = new List<string>();
        protected readonly FXCommonQueryRequest<T> request;

        protected FXBaseQueryService()
        {
            request = new FXCommonQueryRequest<T>
            {
                exceptionHandler = (Exception ex) =>
                {
                    string reason = $"执行[{MethodDescription}]时发生程序错误,";
                    string content = $"错误信息:{ex.Message}, 错误堆栈:{ex.StackTrace}";
                    ErrFunc?.Invoke(reason, content);
                },
                httpRespErrHandler = (CallRoot<T> response, Data queryData) =>
                {
                    string reason = $"执行[{MethodDescription}]时发生请求错误,";
                    string content = $"返回信息:{response.errorMessage}, 请求信息: {queryData}";
                    ErrFunc?.Invoke(reason, content);
                }
            };
        }

        /// <summary>
        /// 获取所有的信息
        /// </summary>
        /// <param name="filters">筛选规则</param>
        /// <param name="orders">排序规则</param>
        /// <returns></returns>
        public virtual List<T> GetAllInfo(List<FiltersItem> filters = null, List<OrdersItem> orders = null)
        {
            return request.GetAllData(ApiName, orders ?? EMPTY_ORDER_RULES, FieldProjection, filters ?? DefaultFilterRules);
        }

        /// <summary>
        /// 处理必填字段缺失
        /// </summary>
        /// <param name="reason"></param>
        /// <param name="lossFields"></param>
        protected virtual void HandleLossFields(string reason, List<string> lossFields)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var fields in lossFields)
            {
                stringBuilder.Append(fields).Append(", ");
            }
            string content = string.Format("必填字段: [{0}]", stringBuilder.ToString());
            ErrFunc(reason, content);
        }

        /// <summary>
        /// 判断是否有必填字段的缺失，有缺失则返回false，没有返回true
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public virtual bool ValidateModel(T model)
        {
            List<string> lossFields = new List<string>();
            foreach (PropertyInfo p in model.GetType().GetProperties())
            {
                if (NecessaryFields.Contains(p.Name) && p.GetValue(model, null) == null)
                {
                    lossFields.Add(p.Name);
                }
            }

            if (lossFields.Count > 0)
            {
                string reason = $"执行{GetType().Name}时[{model.name}]缺少必要字段";
                HandleLossFields(reason, lossFields);
                return false;
            }
            return true;
        }
    }
}
